/************************************************************/
/* Producteur - Consommateur - version du 23/01/2004         */
/*  Realisé par Zayd GHANNAM & Yoram Harmelin & Julie guiraud */ 
/*************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/wait.h>
#include<unistd.h>
#include<signal.h>
#include<errno.h>

#define LG_MAX 1
#define TAILLE_FILE 5
 

struct msgbuf {
  long mtype;         /* type de message */
  char mtext[LG_MAX]; /* contenu du message */
}message;
 

int Nb_Message_File = 0; /* nombre de message dans la file */
int id_file_message;
int nombreDeTours; /* longueur du message à envoyer */


/************************* AFFICHAGE *********************************/

void afficherTitre ()
 { 
  printf ("\n");
  printf ("\n");
  printf ("+--------------+--------------+------------------+\n");
  printf ("|  Producteur  | Consommateur | File de messages |\n");
  printf ("|              |              |                  |\n");
  printf ("|              |              |     Elem E/R     |\n");
  printf ("+--------------+--------------+---------+--------+\n");
 }

void afficherDernierLigne(){
  printf ("+--------------+--------------+---------+--------+\n");
}


/*********************** Traitement du signal ************************/


void StartSignal(int sgn)
{
  if(sgn==SIGUSR1)
  {
    Nb_Message_File--; //on decremente le nombre d'elements ds la file
  }else
	  {
		printf("sgn vaut %d\n",sgn);
	  }
}

void StopSignal(int sgn)
{
   
}

/*************************** Reception element *********************/
char Rcv_Element()
	{ 
	int control;
control=msgrcv(id_file_message, &message, LG_MAX+1, 0, 0);
if(control==-1){perror("Erreur au niveau du msgrcv");}
return (char)(message.mtext);
	}

/*************************** Envoie element *********************/
void Send_Element()
	{
	int control;
 
control=msgsnd(id_file_message, &message, strlen(message.mtext) + 1, 0);
if(control==-1){perror("Erreur au niveau du msgsnd");}
	}


/******************************* Producteur *******************************/
int Producteur(int id_file_message, int nombreDeTours, char* chaineAEnvoyer)
{
  int control,tour;
//declaration structure pour le traitement de signal 

  struct sigaction seg;
  seg.sa_handler = StartSignal;
  sigemptyset (&(seg.sa_mask));
  seg.sa_flags = 0;

  message.mtype = getpid();
 
  for(tour=0; tour < nombreDeTours; tour++){
   	 if(Nb_Message_File<TAILLE_FILE){
    	  message.mtext[0] = *(chaineAEnvoyer+tour);
     	  Send_Element();
      	  Nb_Message_File++;
  printf ("| Placer       |              |   %s     |        |\n",message.mtext);
      
        }else{
           tour--;
          pause();
         if(sigaction(SIGUSR1, &seg, NULL) != 0){
fprintf(stderr,"Erreur de gestion  signaux %d\n",errno);
	exit (1);
      }
    }
  }
  return 0;
}  




/******************************* Consommateur ******************************/
char* Consommateur(int id_file_message, int nombreDeTours)
{
  int control,tour;
  char *chaineRecue = malloc(nombreDeTours); 

  for(tour=0; tour < nombreDeTours; tour++){
    control = Rcv_Element();
    *(chaineRecue+tour) = message.mtext[0];
     kill(getppid(),SIGUSR1);
 
printf ("|              | Retirer      |   %s     |        | \n", message.mtext);
  
  }
  return chaineRecue;
}  



/******************************* MAIN *******************************/


int main(int argc, char* argv[]){

  int cumulDesLongueurs = 0;
  int mot = 1;
  int  delete,attente,etat;
  char* chaineAEnvoyer;
  char* chaineRecue;
 

    for (mot=1; mot<argc; mot++)
      cumulDesLongueurs = cumulDesLongueurs + strlen (*(argv+mot)) + 1;

    chaineAEnvoyer = malloc (cumulDesLongueurs);
    chaineRecue = malloc (cumulDesLongueurs);

    for (mot=1; mot<argc; mot++){
      strcat (chaineAEnvoyer, *(argv+mot));
      strcat (chaineAEnvoyer, " ");
    }
    printf ("\n\nChaine a envoyer : %s\n", chaineAEnvoyer);
  
    nombreDeTours = strlen(chaineAEnvoyer)-1;
	
	//Creation de la file 
   
 id_file_message=msgget(IPC_PRIVATE,0666|IPC_CREAT|IPC_EXCL);
 if(id_file_message==-1) {perror("msgget");}

  
    afficherTitre();
    
	int pid = fork ();

    if (pid == -1)
	{
      perror (" Echec dans la creation du fils");
	 }else
	{
      if (pid== 0)
	  {       

		chaineRecue = Consommateur(id_file_message,nombreDeTours);
		afficherDernierLigne();
		printf("\n\n la chaine recue est: %s\n",chaineRecue);
		  }else
				{
	//  si on recoit le signal SIGUSR1 on effectue le traitement
					signal(SIGUSR1,StartSignal);

					 Producteur(id_file_message,nombreDeTours,chaineAEnvoyer);
					
	//on stop le traitemen du signal SIGUSER1 
					signal(SIGUSR1,StopSignal);

					attente = wait(&etat);  
	
				if (attente==-1)
				  {
					exit(EXIT_FAILURE);//en cas d'erreur d'attente on sort du prog
				  }else
						{

					//destruction de la file
					 delete = msgctl(id_file_message, IPC_RMID, NULL);
						}
				 }
	}
  return 0;
}  

